package com.astrob.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;

import com.astrob.NavFrameSDK.POIDescription;
import com.astrob.model.LonLat;
import com.astrob.naviframe.Start;
import com.astrob.util.Utils;

import java.util.ArrayList;

public class MapViewS extends View {

    public interface MapCallBack {
        // 在地图上显示新增的icon
        void drawOverlay(Canvas canvas, float ws);

        // 在地图上显示新增的icon--单击移图到地图中心并且弹出tipinfo（如果点击处有icon则地图中心做修正）
        void popTipInfo(POIDescription data); //

        // 移图进入移图模式
        void moveMap(boolean removeTip);

        //长按不移图
        void longPress(LonLat ll);

        //双击
        void doubleClick(LonLat ll);

        //单击 单击后
        void singleClick(LonLat ll, Point tipPoint);

        //移图后抬起
        void touchUp();
    }

    boolean mNeedPopTipInfo = true;//如果不需要弹出tip，则回调singleClick

    boolean isClickcenter = false;//是否单击移图到地图中心

    public void setNeedPopTipInfo(boolean showTip) {
        mNeedPopTipInfo = showTip;
    }

    Context mContext;
    GestureDetector mGesture;
    Scroller mScroller;
    boolean mIsFlinging;

    boolean _isMoving = false;

    public MapCallBack mCallback = null;

    public MapViewS(Context context) {
        super(context);
        init(context);
    }

    public MapViewS(Context context, AttributeSet attr) {
        super(context, attr);
        init(context);
    }

    private void init(Context context) {
        mContext = context;
        mGesture = new GestureDetector(context,
                new MapViewGestureDetectorListener());
        mGesture.setOnDoubleTapListener(new MapViewDoubleClickListener());
        mScroller = new Scroller(context);
    }

    public void recycleMap() {
        if (mBitmapMap != null) {
            mBitmapMap.recycle();
        }

        mBuffer = null;
        mBitmapMap = null;
    }

    private java.nio.ByteBuffer mBuffer = null;
    private Bitmap mBitmapMap = null;
    public float _ws = 2;
    public int _mapWidth = 0;
    public int _mapHeight = 0;

    public static int _lastHeight = 0;//检测地图主窗口高度是否变化

    private void initBuffer() {
        if (_lastHeight != this.getHeight()) {
            recycleMap();
        }
        if (mBuffer == null) {
            // 1 dp 相当多少 px
            _ws = mContext.getResources().getDisplayMetrics().density;
            int w = this.getWidth();
            int h = this.getHeight();

            if (w > 500 && _ws < 2) {
                _ws = 2;
            }

            if (w == 1200) {
                _ws = 3;
            }

            _mapWidth = (int) (this.getWidth() / _ws + 0.5);
            _mapHeight = (int) (this.getHeight() / _ws + 0.5);
//            _mapWidth = _mapWidth >> 2 << 2;
//            _mapHeight = _mapHeight >> 2 << 2;
            mBuffer = java.nio.ByteBuffer.allocate(_mapWidth * _mapHeight * 2);
            Start.getInstance().MapKit().setMapSize(_mapWidth, _mapHeight);
            mBitmapMap = Bitmap.createBitmap(_mapWidth, _mapHeight,
                    Bitmap.Config.RGB_565);

            _lastHeight = this.getHeight();
            generateMap();

            //记录log
//            String msg = String.format("density=%f\n_ws=%f\n_mapWidth=%d\n_mapHeight=%d\nw=%d\nh=%d\n",
//                    mContext.getResources().getDisplayMetrics().density,
//                    _ws,
//                    _mapWidth,
//                    _mapHeight,
//                    w,
//                    h
//            );
//            Start.getInstance().log(msg);
        }
    }

    public void updateMap() {
        mHandler.sendEmptyMessage(UPDATEMAP);
    }

    public void generateMap() {
        if (mBuffer == null) {
            return;
        }
        Start.getInstance().MapKit().drawMap(1, mBuffer.array());
        mBuffer.rewind();

        try {
            mBitmapMap.copyPixelsFromBuffer(mBuffer);
        } catch (Exception e) {
            return;
        }
    }

    double _maxLon, _maxLat, _minLon, _minLat;

    // 点在显示地图范围内
    public boolean isInMapRegion(LonLat ll) {
        if (ll.GetLon() > _maxLon || ll.GetLat() > _maxLat
                || ll.GetLon() < _minLon || ll.GetLat() < _minLat) {
            return false;
        }

        return true;
    }

    //地图四个角的经纬度0-左上 1-右上 2-右下 3-左下
    public ArrayList<LonLat> llRect = new ArrayList<LonLat>();

    public double[] getMapRegion() {
        double[] regions = {_maxLon, _maxLat, _minLon, _minLat};
        return regions;
    }

    void setMapRegion() {
        _maxLon = -180;
        _maxLat = 0;
        _minLon = 180;
        _minLat = 90;
        llRect.clear();
        Point pos = new Point(0, 0); // top-left
        for (int i = 0; i < 4; i++) {
            if (i == 1) {
                // top-right
                pos.x = _mapWidth;
                pos.y = 0;
            } else if (i == 2) {
                // bottom-left
                pos.x = 0;
                pos.y = _mapHeight;
            } else if (i == 3) {
                // bottom-right
                pos.x = _mapWidth;
                pos.y = _mapHeight;
            }

            LonLat ll = Start.getInstance().MapKit().XY2LL(pos);
            llRect.add(ll);
            double lon = ll.GetLon();
            double lat = ll.GetLat();
            if (_maxLon < lon) {
                _maxLon = lon;
            }
            if (_maxLat < lat) {
                _maxLat = lat;
            }
            if (_minLon > lon) {
                _minLon = lon;
            }
            if (_minLat > lat) {
                _minLat = lat;
            }
        }

        // 加大一些范围
        _maxLon = _maxLon + 0.01;
        _maxLat = _maxLat + 0.01;
        _minLon = _minLon - 0.01;
        _minLat = _minLat - 0.01;
    }

    @Override
    public void onDraw(Canvas canvas) {
        initBuffer();
        setMapRegion();

        if (mBitmapMap != null) {
            Drawable drawable = new BitmapDrawable(mContext.getResources(), mBitmapMap);
            drawable.setBounds(0, 0, this.getWidth(), this.getHeight());
            drawable.draw(canvas);

            if (mCallback != null) {
                mCallback.drawOverlay(canvas, _ws);
            }
        }

        super.onDraw(canvas);
    }

    private int _mode = 0;
    float _oldDist;

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(final MotionEvent event) {

        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                _mode = 1;
                break;
            case MotionEvent.ACTION_UP:
                _mode = 0;
                if (mCallback != null) {
                    mCallback.touchUp();
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                _mode -= 1;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                _oldDist = (float) Utils.spacing(event);
                _mode += 1;
                break;
            case MotionEvent.ACTION_MOVE:
                if (_mode >= 2) {
                    float newDist = (float) Utils.spacing(event);
                    if (newDist > _oldDist + 1) {
                        zoom(newDist / _oldDist);
                        _oldDist = newDist;
                    }
                    if (newDist < _oldDist - 1) {
                        zoom(newDist / _oldDist);
                        _oldDist = newDist;
                    }
                    return true;
                }
                break;
        }

        return mGesture.onTouchEvent(event);
    }

    private static final int UPDATEMAP = 601;

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case UPDATEMAP:
                    generateMap();
                    invalidate();
                    break;
            }
        }
    };

    private class MapViewGestureDetectorListener implements OnGestureListener {

        @Override
        public boolean onDown(final MotionEvent e) {
            if (mIsFlinging) {
                mScroller.abortAnimation();
                mIsFlinging = false;
            }
            return true;
        }

        // Touch了滑动一点距离后，up时触发
        @Override
        public boolean onFling(final MotionEvent e1, final MotionEvent e2,
                               final float velocityX, final float velocityY) {
            // velocityX：X轴上的移动速度，像素/秒
            // velocityY：Y轴上的移动速度，像素/秒
//            mIsFlinging = true;
//            mScroller.fling(getScrollX(), getScrollY(), (int) -velocityX,
//                    (int) -velocityY, -100, 100, -100, 100);
//            return true;
            return false;
        }

        @Override
        public void onLongPress(final MotionEvent e) {
            //长按
            Point tipPoint = new Point();
            tipPoint.set((int) (e.getX() / _ws), (int) (e.getY() / _ws));
            LonLat ll = Start.getInstance().MapKit().XY2LL(tipPoint);
            if (mCallback != null) {
                mCallback.longPress(ll);
                mCallback.moveMap(false);
            }
        }

        // Touch了滑动时触发
        @Override
        public boolean onScroll(final MotionEvent e1, final MotionEvent e2,
                                final float distanceX, final float distanceY) {
            moveMap((int) (-distanceX / _ws), (int) (-distanceY / _ws));
            return true;
        }

        @Override
        public void onShowPress(final MotionEvent e) {

        }

        @Override
        public boolean onSingleTapUp(final MotionEvent e) {

            return true;
        }

    }

    private class MapViewDoubleClickListener implements
            GestureDetector.OnDoubleTapListener {
        @Override
        public boolean onDoubleTap(final MotionEvent e) {
//            zoomInFixing((int) (e.getX() / _ws), (int) (e.getY() / _ws));
            if (mCallback != null) {
                Point point = new Point();
                point.set((int) (e.getX() / _ws), (int) (e.getY() / _ws));
                LonLat ll = Start.getInstance().MapKit().XY2LL(point);
                mCallback.doubleClick(ll);
            }
            return true;
        }

        @Override
        public boolean onDoubleTapEvent(final MotionEvent e) {
            return false;
        }

        @Override
        public boolean onSingleTapConfirmed(final MotionEvent e) {
            Point tipPoint = new Point();
            tipPoint.set((int) (e.getX() / _ws), (int) (e.getY() / _ws));
            if (mNeedPopTipInfo) {
                changeTipLL(Start.getInstance().MapKit().XY2LL(tipPoint));
            } else if (mCallback != null) {
                LonLat ll = Start.getInstance().MapKit().XY2LL(tipPoint);
                mCallback.singleClick(ll, new Point((int)e.getX(), (int)e.getY()));
            }
            return true;
        }
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            int x = mScroller.getCurrX();
            int y = mScroller.getCurrY();
            if (mScroller.isFinished()) {
                mIsFlinging = false;
            }
//            moveMap((int) (-x / _ws), (int) (-y / _ws));
        }
    }

    // 引擎相关
    void moveMap(int dx, int dy) {
        if (mCallback != null) {
            mCallback.moveMap(true);
        }

        Start.getInstance().MapKit().moveMap(dx, dy);
        generateMap();
        invalidate();
    }

    void zoom(float f) {
        mScroller.forceFinished(true);
        mIsFlinging = false;

        Start.getInstance().MapKit().zoomScale(f);
        generateMap();
        invalidate();
    }

    boolean zoomInFixing(int x, int y) {
        Point point = new Point();
        point.set(x, y);
        LonLat ll = Start.getInstance().MapKit().XY2LL(point);
        Start.getInstance().MapKit().onZoomIn();
        Start.getInstance().MapKit().setPosition(point, ll);
        generateMap();
        invalidate();
        return true;
    }

    // 点击地图查询最近的显示poi，将选中的poi放到地图中心
    void changeTipLL(LonLat tipLL) {
        if (tipLL == null) {
            return;
        }
        //5米以内的poi
        Start.getInstance().MapKit().mTipPoiList = Start.getInstance().MapKit()
                .getNearPoi(tipLL, true);

        if (Start.getInstance().MapKit().mTipPoiList.size() < 1)
            return;
        POIDescription data = Start.getInstance().MapKit().mTipPoiList.get(0);
        if (data.pcode.length > 0) {
            tipLL.SetLonLat(data.position.lon, data.position.lat);
        }

        if (isClickcenter) {
            Start.getInstance().MapKit().setMapCenter(tipLL);
        }
        generateMap();
        invalidate();

        if (mCallback != null) {
            mCallback.popTipInfo(data);
            mCallback.moveMap(false);
        }
    }

}
